package pl.edu.agh.iosr.gamblingzone.dao.ejb;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;

import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;

import org.hibernate.Criteria;
import org.hibernate.LockMode;
import org.hibernate.Session;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Example;
import org.jboss.seam.annotations.In;

import pl.edu.agh.iosr.gamblingzone.dao.GenericDAO;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import java.util.List;

public abstract class GenericEJBDAO<T,ID extends Serializable>
		implements GenericDAO<T, ID> {
	
	private Class<T> entityBeanType;

	private EntityManager entityManager;
	
	public GenericEJBDAO() {
		this.entityBeanType = (Class<T>) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0];
	}
	
	public void setEntityManager(EntityManager entityManager) {
		this.entityManager = entityManager;
	}
	
	protected EntityManager getEntityManager() {
		if (entityManager == null)
		    throw new IllegalStateException("EntityManager has not been set on DAO before usage");
		return entityManager;
	}
	
	public Class<T> getEntityBeanType() {
		return entityBeanType;
	}
	
//	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public T findById(ID id, boolean lock) {
		T entity;
		if (lock) {
		    entity = getEntityManager().find(getEntityBeanType(), id);
		    entityManager.lock(entity, javax.persistence.LockModeType.WRITE);
		} else {
		    entity = getEntityManager().find(getEntityBeanType(), id);
		}
		return entity;
	}
	
	@SuppressWarnings("unchecked")
//	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public List<T> findAll() {
		return getEntityManager().createQuery("from " + getEntityBeanType().getName() ).getResultList();
	}
	
	
	@SuppressWarnings("unchecked")
//	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public List<T> findByExample(T exampleInstance, String... excludeProperty) {
		return null;
	}
	
	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public T makePersistent(T entity) {
		return getEntityManager().merge(entity);
	}
	
//	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public void makeTransient(T entity) {
		getEntityManager().remove(entity);
	}
	
//	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public void flush() {
		getEntityManager().flush();
	}
	
//	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public void clear() {
		getEntityManager().clear();
	}
	
	/**
	* Use this inside subclasses as a convenience method.
	*/
	@SuppressWarnings("unchecked")
//	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	protected List<T> findByCriteria(org.hibernate.criterion.Criterion... criterion) {
		return null;
	}

}
